Skip to main content
A snapshot represents the state of your backed-up data at a specific point in time. Snapshots are the primary way you interact with your backup history in rustic_core.

What is a Snapshot?

A snapshot is metadata that describes:
  • When the backup was taken
  • What was backed up (paths)
  • Where it came from (hostname)
  • How to find the data (tree ID)
  • Who created it (username)
  • Why it exists (tags, labels, description)
Snapshots are stored as JSON files in the repository’s snapshots/ directory. Each snapshot is identified by a unique 32-byte ID.

Snapshot Metadata

The SnapshotFile structure contains comprehensive metadata:
pub struct SnapshotFile {
    /// Timestamp of this snapshot
    pub time: Zoned,
    
    /// The tree blob id where contents are stored  
    pub tree: TreeId,
    
    /// The list of paths contained in this snapshot
    pub paths: StringList,
    
    /// The hostname where snapshot was created
    pub hostname: String,
    
    /// Tags for filtering and organization
    pub tags: StringList,
    
    /// Optional label for the snapshot
    pub label: String,
    
    /// Parent snapshot ID for incremental backups
    pub parent: Option<SnapshotId>,
    
    /// Summary statistics from the backup
    pub summary: Option<SnapshotSummary>,
    
    /// Optional description
    pub description: Option<String>,
    
    // ... additional fields
}

Core Fields

The timestamp when the backup was created. This is the primary sorting field for snapshots.
// Snapshots are ordered by time
impl Ord for SnapshotFile {
    fn cmp(&self, other: &Self) -> Ordering {
        self.time.cmp(&other.time)
    }
}
The ID of the root tree blob containing the snapshot’s directory structure and file references. This is how you access the actual backup data.
let tree = repo.get_tree(&snapshot.tree)?;
List of filesystem paths that were backed up in this snapshot.
snapshot.paths  // StringList(["home/user/docs", "/etc"])
User-defined tags for organizing and filtering snapshots.
let tags = StringList::from_str("important,daily")?;
snapshot.add_tags(vec![tags]);

Snapshot Immutability

Snapshots are immutable once created. You cannot modify an existing snapshot’s data or metadata.
This immutability provides:
  • Integrity: Snapshots cannot be corrupted or tampered with
  • Consistency: What you backed up is what you’ll restore
  • Audit trail: Complete history of all backups
If you need to “modify” a snapshot (e.g., add tags), rustic creates a new snapshot with the updated metadata:
// Modifying creates a new snapshot
pub fn modify(&mut self, modification: &SnapshotModification) -> RusticResult<bool> {
    modification.apply_to(self)  // Returns true if changed
}

// Original snapshot ID stored for reference
pub original: Option<SnapshotId>,

Incremental Snapshots

Snapshots support incremental backups through parent relationships:
1

First Backup

Initial snapshot with no parent backs up all data.
let snapshot = SnapshotFile {
    parent: None,  // No parent
    // ...
};
2

Incremental Backup

Subsequent backups reference the previous snapshot as parent.
let snapshot = SnapshotFile {
    parent: Some(previous_snapshot_id),
    // Only changed files are stored
};
3

Deduplication

Unchanged files reference existing blobs, saving space.rustic_core automatically detects unchanged files by comparing:
  • File size
  • Modification time
  • Inode (when available)
Each snapshot is self-contained and can be restored independently, even if you delete the parent snapshots!

Snapshot Organization

Finding Snapshots

Multiple ways to identify and retrieve snapshots:
Use full or partial snapshot ID:
// Full ID
let snap = repo.get_snapshot_from_str(
    "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    |_| true
)?;

// Partial ID (must be unique)
let snap = repo.get_snapshot_from_str("0123456", |_| true)?;

Filtering Snapshots

Snapshots can be filtered using custom predicates:
// By hostname
let filter = |snap: &SnapshotFile| snap.hostname == "production";
let snaps = repo.get_matching_snapshots(filter)?;

// By tags
let required_tags = vec![StringList::from_str("daily,important")?];
let filter = |snap: &SnapshotFile| snap.tags.matches(&required_tags);

// By time range
let cutoff = Zoned::now().checked_sub(30.days())?;
let filter = |snap: &SnapshotFile| snap.time > cutoff;

Snapshot Summary

The optional SnapshotSummary provides detailed statistics about the backup:
pub struct SnapshotSummary {
    // File statistics
    pub files_new: u64,
    pub files_changed: u64,
    pub files_unmodified: u64,
    pub total_files_processed: u64,
    pub total_bytes_processed: u64,
    
    // Directory statistics  
    pub dirs_new: u64,
    pub dirs_changed: u64,
    pub dirs_unmodified: u64,
    
    // Blob statistics
    pub data_blobs: u64,
    pub tree_blobs: u64,
    pub data_added: u64,              // Uncompressed
    pub data_added_packed: u64,        // Compressed
    
    // Timing
    pub backup_start: Zoned,
    pub backup_end: Zoned,
    pub backup_duration: f64,
}

Example Summary

{
  "total_files_processed": 15234,
  "files_new": 42,
  "files_changed": 156,
  "files_unmodified": 15036,
  "data_added": 2147483648,
  "data_added_packed": 536870912,
  "backup_duration": 45.2
}
This shows good deduplication: 2GB of data compressed to ~512MB.

Snapshot Lifecycle

Creating Snapshots

Snapshots are created during backup operations:
use rustic_core::{SnapshotOptions, SnapshotFile};

// Configure snapshot metadata
let snap_opts = SnapshotOptions {
    label: Some("Daily Backup".to_string()),
    tags: vec![StringList::from_str("daily,automated")?],
    description: Some("Automated daily backup".to_string()),
    ..Default::default()
};

// Create snapshot from options
let snapshot = SnapshotFile::from_options(&snap_opts)?;

Deleting Snapshots

Snapshots can be removed (respecting deletion policies):
// Check if snapshot must be kept
if snapshot.must_keep(&Zoned::now()) {
    println!("Cannot delete: snapshot has deletion protection");
} else {
    repo.delete_snapshots(&[snapshot.id])?;
}
Deleting snapshots only removes the metadata. The actual data blobs are removed during prune operations.

Deletion Policies

Snapshots support deletion policies:
pub enum DeleteOption {
    NotSet,                    // No policy
    Never,                     // Never delete
    After(Zoned),             // Delete after this time
}
Example usage:
// Mark as permanent
let snap_opts = SnapshotOptions {
    delete_never: true,
    ..Default::default()
};

// Auto-delete after 30 days
let snap_opts = SnapshotOptions {
    delete_after: Some(Span::new().days(30)),
    ..Default::default()  
};

Multiple Parents

Snapshots can have multiple parents for advanced scenarios:
pub struct SnapshotFile {
    pub parent: Option<SnapshotId>,     // Single parent (legacy)
    pub parents: Vec<SnapshotId>,       // Multiple parents
}

// Get all parents
let parents = snapshot.get_parents();  // Returns &[SnapshotId]
This enables:
  • Merged snapshots: Combining multiple backup sources
  • Migration: Preserving history when moving repositories

See Also

Repository

Learn about repository structure

Deduplication

How rustic eliminates duplicate data

Encryption

Snapshot security and encryption

Backends

Where snapshots are stored